/*****************************************************************************
*        描述 :
*             文件描述
*        CLR版本:            3.5
*        创建者 :            蒋 光
*        个人域名:           jiangguang.net.cn
*        命名空间名称:       ECP.DataAccess
*        文件名:             BaseSequenceDao.cs
*        创建系统时间:       2012/11/2 19:07:00
*        创建年份:           2012
*
/*****************************************************************************/

namespace ECP.DataAccess
{
    using System;
    using System.Data;
    using System.Threading;
    using ECP.DataAccess.Utilities;
    using ECP.Model;
    using ECP.Utilities;

    public class BaseSequenceDao : BaseDao, IBaseDao
    {
        public int DefaultDegression;
        public string DefaultPrefix;
        public string DefaultSeparate;
        public int DefaultSequence;
        public int DefaultSequenceLength;
        public int DefaultStep;
        public bool FillZeroPrefix;
        private static BaseSequenceDao instance = null;
        private static object locker = new object();
        public int SequenceLength;
        public bool UsePrefix;

        public BaseSequenceDao()
        {
            this.FillZeroPrefix = true;
            this.DefaultSequence = 0x989680;
            this.DefaultDegression = 0x98967f;
            this.DefaultPrefix = "";
            this.DefaultSeparate = "";
            this.DefaultStep = 1;
            this.DefaultSequenceLength = 8;
            this.SequenceLength = 8;
            this.UsePrefix = true;
            base.CurrentTableName = BaseSequenceTable.TableName;
        }

        public BaseSequenceDao(IDbHelper dbHelper)
            : this()
        {
            base.DbHelper = dbHelper;
        }

        public BaseSequenceDao(IDbHelper dbHelper, BaseUserInfo userInfo)
            : this(dbHelper)
        {
            base.UserInfo = userInfo;
        }

        public string Add(IDbHelper dbHelper, string fullName)
        {
            return this.AddEntity(dbHelper, fullName, this.DefaultSequence);
        }

        public string Add(BaseSequenceEntity sequenceEntity, out string statusCode)
        {
            string str = string.Empty;
            if (this.Exists(BaseSequenceTable.FieldFullName, sequenceEntity.FullName))
            {
                statusCode = StatusCode.ErrorFullNameExist.ToString();
                return str;
            }
            str = this.AddEntity(sequenceEntity);
            statusCode = StatusCode.OKAdd.ToString();
            return str;
        }

        public string Add(IDbHelper dbHelper, string fullName, int defaultSequence)
        {
            return this.AddEntity(dbHelper, fullName, defaultSequence);
        }

        public string AddEntity(BaseSequenceEntity sequenceEntity)
        {
            if (string.IsNullOrEmpty(sequenceEntity.ID))
            {
                string sequence = Instance.GetSequence(base.DbHelper, BaseSequenceTable.TableName);
                if (string.IsNullOrEmpty(sequenceEntity.ID))
                {
                    sequenceEntity.ID = sequence;
                }
            }
            SQLBuilder builder = new SQLBuilder(base.DbHelper);
            builder.BeginInsert(BaseSequenceTable.TableName);
            builder.SetValue(BaseSequenceTable.FieldID, sequenceEntity.ID);
            builder.SetValue(BaseSequenceTable.FieldFullName, sequenceEntity.FullName);
            builder.SetValue(BaseSequenceTable.FieldPrefix, sequenceEntity.Prefix);
            builder.SetValue(BaseSequenceTable.FieldSeparate, sequenceEntity.Separate);
            builder.SetValue(BaseSequenceTable.FieldSequence, sequenceEntity.Sequence);
            builder.SetValue(BaseSequenceTable.FieldDegression, sequenceEntity.Degression);
            builder.SetValue(BaseSequenceTable.FieldStep, sequenceEntity.Step);
            builder.SetValue(BaseSequenceTable.FieldDescription, sequenceEntity.Description);
            if (builder.EndInsert() <= 0)
            {
                return string.Empty;
            }
            return sequenceEntity.ID;
        }

        public string AddEntity(IDbHelper dbHelper, string fullName, int defaultSequence)
        {
            string sequence = this.GetSequence(dbHelper, BaseSequenceTable.TableName);
            SQLBuilder builder = new SQLBuilder(dbHelper);
            builder.BeginInsert(BaseSequenceTable.TableName);
            builder.SetValue(BaseSequenceTable.FieldID, sequence);
            builder.SetValue(BaseSequenceTable.FieldFullName, fullName);
            builder.SetValue(BaseSequenceTable.FieldPrefix, this.DefaultPrefix);
            builder.SetValue(BaseSequenceTable.FieldSeparate, this.DefaultSeparate);
            builder.SetValue(BaseSequenceTable.FieldSequence, defaultSequence);
            builder.SetValue(BaseSequenceTable.FieldDegression, this.DefaultDegression);
            builder.SetValue(BaseSequenceTable.FieldStep, this.DefaultStep);
            if (builder.EndInsert() <= 0)
            {
                return string.Empty;
            }
            return this.DefaultSequence.ToString();
        }

        public int Delete(IDbHelper dbHelper, string fullName)
        {
            base.DbHelper = dbHelper;
            return this.Delete(BaseSequenceTable.FieldFullName, fullName);
        }

        public string[] GetBatchSequence(IDbHelper dbHelper, string fullName, int sequenceCount)
        {
            return this.GetBatchSequence(dbHelper, fullName, sequenceCount, this.DefaultSequence);
        }

        public string[] GetBatchSequence(IDbHelper dbHelper, string fullName, int sequenceCount, int defaultSequence)
        {
            string[] sequence = new string[sequenceCount];
            BaseSequenceEntity sequenceEntity = null;
            switch (BaseConfiguration.Instance.DataBaseType)
            {
                case DataBaseType.Oracle:
                    if (!dbHelper.InTransaction)
                    {
                        try
                        {
                            dbHelper.BeginTransaction();
                            base.ReturnStatusCode = StatusCode.CanNotLock.ToString();
                            sequenceEntity = this.GetOldSequenceDegressionByLock(dbHelper, fullName, defaultSequence);
                            if (base.ReturnStatusCode == StatusCode.LockOK.ToString())
                            {
                                base.ReturnStatusCode = StatusCode.CanNotLock.ToString();
                                if (this.UpdateSequence(dbHelper, fullName, sequenceCount) > 0)
                                {
                                    dbHelper.CommitTransaction();
                                    base.ReturnStatusCode = StatusCode.LockOK.ToString();
                                    return this.GetSequence(sequenceEntity, sequenceCount);
                                }
                                dbHelper.RollbackTransaction();
                                return sequence;
                            }
                            dbHelper.RollbackTransaction();
                        }
                        catch
                        {
                            dbHelper.RollbackTransaction();
                            base.ReturnStatusCode = StatusCode.CanNotLock.ToString();
                            sequence = new string[sequenceCount];
                        }
                        return sequence;
                    }
                    sequenceEntity = this.GetOldSequenceDegressionByLock(dbHelper, fullName, defaultSequence);
                    if (base.ReturnStatusCode == StatusCode.LockOK.ToString())
                    {
                        if (this.UpdateSequence(dbHelper, fullName, sequenceCount) <= 0)
                        {
                            base.ReturnStatusCode = StatusCode.CanNotLock.ToString();
                            return sequence;
                        }
                        base.ReturnStatusCode = StatusCode.LockOK.ToString();
                        sequence = this.GetSequence(sequenceEntity, sequenceCount);
                    }
                    return sequence;

                case DataBaseType.Sqlserver:
                case DataBaseType.Access:
                case DataBaseType.MySql:
                    sequenceEntity = this.GetOldSequenceDegression(dbHelper, fullName, defaultSequence, this.DefaultSequenceLength, this.FillZeroPrefix);
                    this.UpdateSequence(dbHelper, fullName, sequenceCount);
                    return this.GetSequence(sequenceEntity, sequenceCount);

                case DataBaseType.Bd2:
                    return sequence;
            }
            return sequence;
        }

        public string GetDegression(IDbHelper dbHelper, string fullName)
        {
            return this.GetDegression(dbHelper, fullName, this.DefaultSequence);
        }

        public string GetDegression(IDbHelper dbHelper, string fullName, int defaultSequence)
        {
            BaseSequenceEntity entity = new BaseSequenceEntity();
            switch (BaseConfiguration.Instance.DataBaseType)
            {
                case DataBaseType.Oracle:
                    if (!dbHelper.InTransaction)
                    {
                        try
                        {
                            dbHelper.BeginTransaction();
                            base.ReturnStatusCode = StatusCode.CanNotLock.ToString();
                            entity = this.GetOldSequenceDegressionByLock(dbHelper, fullName, defaultSequence);
                            if (base.ReturnStatusCode == StatusCode.LockOK.ToString())
                            {
                                base.ReturnStatusCode = StatusCode.CanNotLock.ToString();
                                if (this.UpdateDegression(dbHelper, fullName) > 0)
                                {
                                    dbHelper.CommitTransaction();
                                    base.ReturnStatusCode = StatusCode.LockOK.ToString();
                                }
                                else
                                {
                                    dbHelper.RollbackTransaction();
                                }
                            }
                            else
                            {
                                dbHelper.RollbackTransaction();
                            }
                        }
                        catch
                        {
                            dbHelper.RollbackTransaction();
                            base.ReturnStatusCode = StatusCode.CanNotLock.ToString();
                        }
                        break;
                    }
                    entity = this.GetOldSequenceDegressionByLock(dbHelper, fullName, defaultSequence);
                    if (base.ReturnStatusCode == StatusCode.LockOK.ToString())
                    {
                        if (this.UpdateDegression(dbHelper, fullName) <= 0)
                        {
                            base.ReturnStatusCode = StatusCode.CanNotLock.ToString();
                            break;
                        }
                        base.ReturnStatusCode = StatusCode.LockOK.ToString();
                    }
                    break;

                case DataBaseType.Sqlserver:
                case DataBaseType.Access:
                case DataBaseType.MySql:
                    entity = this.GetOldSequenceDegression(dbHelper, fullName, defaultSequence, this.DefaultSequenceLength, this.FillZeroPrefix);
                    this.UpdateDegression(dbHelper, fullName);
                    break;
            }
            return entity.OldDegression;
        }

        public BaseSequenceEntity GetEntity(IDbHelper dbHelper, string fullName)
        {
            BaseSequenceEntity entity = null;
            base.DbHelper = dbHelper;
            DataTable dataTable = this.Get(BaseSequenceTable.FieldFullName, fullName);
            if (dataTable.Rows.Count > 0)
            {
                entity = new BaseSequenceEntity(dataTable);
            }
            return entity;
        }

        public string GetOldSequence(IDbHelper dbHelper, string fullName)
        {
            return this.GetOldSequence(dbHelper, fullName, this.DefaultSequence, this.DefaultSequenceLength, this.FillZeroPrefix);
        }

        public string GetOldSequence(IDbHelper dbHelper, string fullName, int defaultSequence)
        {
            return this.GetOldSequence(dbHelper, fullName, defaultSequence, this.DefaultSequenceLength, this.FillZeroPrefix);
        }

        public string GetOldSequence(IDbHelper dbHelper, string fullName, int defaultSequence, int sequenceLength)
        {
            return this.GetOldSequence(dbHelper, fullName, defaultSequence, sequenceLength, false);
        }

        public string GetOldSequence(IDbHelper dbHelper, string fullName, int defaultSequence, int sequenceLength, bool fillZeroPrefix)
        {
            return this.GetOldSequenceDegression(dbHelper, fullName, defaultSequence, sequenceLength, fillZeroPrefix).OldSequence;
        }

        protected BaseSequenceEntity GetOldSequenceDegression(IDbHelper dbHelper, string fullName, int defaultSequence, int sequenceLength, bool fillZeroPrefix)
        {
            BaseSequenceEntity entity = this.GetEntity(dbHelper, fullName);
            if (entity == null)
            {
                this.Add(dbHelper, fullName, defaultSequence);
                entity = this.GetEntity(dbHelper, fullName);
            }
            entity.SequenceLength = sequenceLength;
            entity.FillZeroPrefix = fillZeroPrefix;
            return entity;
        }

        protected BaseSequenceEntity GetOldSequenceDegressionByLock(IDbHelper dbHelper, string fullName, int defaultSequence)
        {
            BaseSequenceEntity entity = new BaseSequenceEntity();
            entity = this.GetEntity(dbHelper, fullName);
            if (entity != null)
            {
                base.ReturnStatusCode = StatusCode.CanNotLock.ToString();
                for (int j = 0; j < BaseSystemInfo.LockNoWaitCount; j++)
                {
                    if (DbLogic.LockNoWait(dbHelper, BaseSequenceTable.TableName, BaseSequenceTable.FieldFullName, fullName) > 0)
                    {
                        entity = this.GetEntity(dbHelper, fullName);
                        base.ReturnStatusCode = StatusCode.LockOK.ToString();
                        return entity;
                    }
                    Thread.Sleep(BaseRandom.GetRandom(1, BaseSystemInfo.LockNoWaitTickMilliSeconds));
                }
                return entity;
            }
            base.ReturnStatusCode = StatusCode.CanNotLock.ToString();
            for (int i = 0; i < BaseSystemInfo.LockNoWaitCount; i++)
            {
                if (DbLogic.LockNoWait(dbHelper, BaseSequenceTable.TableName, BaseSequenceTable.FieldFullName, BaseSequenceTable.TableName) > 0)
                {
                    this.Add(dbHelper, fullName, defaultSequence);
                    base.ReturnStatusCode = StatusCode.LockOK.ToString();
                    break;
                }
                Thread.Sleep(BaseRandom.GetRandom(1, BaseSystemInfo.LockNoWaitTickMilliSeconds));
            }
            if (base.ReturnStatusCode == StatusCode.LockOK.ToString())
            {
                entity = this.GetEntity(dbHelper, fullName);
            }
            return entity;
        }

        public string GetSequence(IDbHelper dbHelper, string fullName)
        {
            return this.GetSequence(dbHelper, fullName, this.DefaultSequence, this.DefaultSequenceLength, this.FillZeroPrefix);
        }

        private string[] GetSequence(BaseSequenceEntity sequenceEntity, int sequenceCount)
        {
            string[] strArray = new string[sequenceCount];
            for (int i = 0; i < sequenceCount; i++)
            {
                strArray[i] = sequenceEntity.OldSequence;
                sequenceEntity.Sequence += sequenceEntity.Step;
            }
            return strArray;
        }

        public string GetSequence(IDbHelper dbHelper, string fullName, int defaultSequence)
        {
            return this.GetSequence(dbHelper, fullName, defaultSequence, this.DefaultSequenceLength, this.FillZeroPrefix);
        }

        public string GetSequence(IDbHelper dbHelper, string fullName, int defaultSequence, int sequenceLength)
        {
            return this.GetSequence(dbHelper, fullName, defaultSequence, sequenceLength, false);
        }

        public string GetSequence(IDbHelper dbHelper, string fullName, int defaultSequence, int sequenceLength, bool fillZeroPrefix)
        {
            BaseSequenceEntity entity = null;
            switch (BaseConfiguration.Instance.DataBaseType)
            {
                case DataBaseType.Oracle:
                    if (!dbHelper.InTransaction)
                    {
                        try
                        {
                            dbHelper.BeginTransaction();
                            base.ReturnStatusCode = StatusCode.CanNotLock.ToString();
                            entity = this.GetOldSequenceDegressionByLock(dbHelper, fullName, defaultSequence);
                            if (base.ReturnStatusCode == StatusCode.LockOK.ToString())
                            {
                                base.ReturnStatusCode = StatusCode.CanNotLock.ToString();
                                if (this.UpdateSequence(dbHelper, fullName) > 0)
                                {
                                    dbHelper.CommitTransaction();
                                    base.ReturnStatusCode = StatusCode.LockOK.ToString();
                                }
                                else
                                {
                                    dbHelper.RollbackTransaction();
                                }
                            }
                            else
                            {
                                dbHelper.RollbackTransaction();
                            }
                        }
                        catch (Exception exception)
                        {
                            Console.WriteLine(exception);
                            dbHelper.RollbackTransaction();
                            base.ReturnStatusCode = StatusCode.CanNotLock.ToString();
                        }
                        break;
                    }
                    entity = this.GetOldSequenceDegressionByLock(dbHelper, fullName, defaultSequence);
                    if (base.ReturnStatusCode == StatusCode.LockOK.ToString())
                    {
                        if (this.UpdateSequence(dbHelper, fullName) <= 0)
                        {
                            base.ReturnStatusCode = StatusCode.CanNotLock.ToString();
                            break;
                        }
                        base.ReturnStatusCode = StatusCode.LockOK.ToString();
                    }
                    break;

                case DataBaseType.Sqlserver:
                case DataBaseType.Access:
                case DataBaseType.MySql:
                    entity = this.GetOldSequenceDegression(dbHelper, fullName, defaultSequence, sequenceLength, fillZeroPrefix);
                    this.UpdateSequence(dbHelper, fullName);
                    break;
            }
            return entity.OldSequence;
        }

        public string NewGuid()
        {
            return Guid.NewGuid().ToString();
        }

        public int Reset(IDbHelper dbHelper, string[] ids)
        {
            int num = 0;
            SQLBuilder builder = new SQLBuilder(dbHelper);
            for (int i = 0; i < ids.Length; i++)
            {
                if (ids[i].Length > 0)
                {
                    builder.BeginUpdate(BaseSequenceTable.TableName);
                    builder.SetValue(BaseSequenceTable.FieldSequence, this.DefaultSequence);
                    builder.SetValue(BaseSequenceTable.FieldDegression, this.DefaultDegression);
                    builder.SetWhere(BaseSequenceTable.FieldID, ids[i]);
                    num += builder.EndUpdate();
                }
            }
            return num;
        }

        public int Update(BaseSequenceEntity sequenceEntity, out string statusCode)
        {
            int num = 0;
            if (this.Exists(BaseSequenceTable.FieldFullName, sequenceEntity.FullName, sequenceEntity.ID))
            {
                statusCode = StatusCode.ErrorFullNameExist.ToString();
                return num;
            }
            num = this.UpdateEntity(sequenceEntity);
            if (num == 1)
            {
                statusCode = StatusCode.OKUpdate.ToString();
                return num;
            }
            statusCode = StatusCode.ErrorDeleted.ToString();
            return num;
        }

        protected int UpdateDegression(IDbHelper dbHelper, string fullName)
        {
            SQLBuilder builder = new SQLBuilder(dbHelper);
            builder.BeginUpdate(BaseSequenceTable.TableName);
            builder.SetFormula(BaseSequenceTable.FieldDegression, BaseSequenceTable.FieldDegression + " - " + BaseSequenceTable.FieldStep);
            builder.SetWhere(BaseSequenceTable.FieldFullName, fullName);
            return builder.EndUpdate();
        }

        public int UpdateEntity(BaseSequenceEntity sequenceEntity)
        {
            SQLBuilder builder = new SQLBuilder(base.DbHelper);
            builder.BeginUpdate(BaseSequenceTable.TableName);
            builder.SetValue(BaseSequenceTable.FieldFullName, sequenceEntity.FullName);
            builder.SetValue(BaseSequenceTable.FieldPrefix, sequenceEntity.Prefix);
            builder.SetValue(BaseSequenceTable.FieldSeparate, sequenceEntity.Separate);
            builder.SetValue(BaseSequenceTable.FieldSequence, sequenceEntity.Sequence);
            builder.SetValue(BaseSequenceTable.FieldDegression, sequenceEntity.Degression);
            builder.SetValue(BaseSequenceTable.FieldStep, sequenceEntity.Step);
            builder.SetValue(BaseSequenceTable.FieldDescription, sequenceEntity.Description);
            builder.SetWhere(BaseSequenceTable.FieldID, sequenceEntity.ID);
            return builder.EndUpdate();
        }

        protected int UpdateSequence(IDbHelper dbHelper, string fullName)
        {
            return this.UpdateSequence(dbHelper, fullName, 1);
        }

        protected int UpdateSequence(IDbHelper dbHelper, string fullName, int sequenceCount)
        {
            SQLBuilder builder = new SQLBuilder(dbHelper);
            builder.BeginUpdate(BaseSequenceTable.TableName);
            builder.SetFormula(BaseSequenceTable.FieldSequence, BaseSequenceTable.FieldSequence + " + " + sequenceCount.ToString() + " * " + BaseSequenceTable.FieldStep);
            builder.SetWhere(BaseSequenceTable.FieldFullName, fullName);
            return builder.EndUpdate();
        }

        public static BaseSequenceDao Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (locker)
                    {
                        if (instance == null)
                        {
                            instance = new BaseSequenceDao();
                        }
                    }
                }
                return instance;
            }
        }
    }
}